#include "ScenePrecompiled.hxx"
#include "SceneSkeletonContext.hxx"

#include "InternalMeshContextImpl.hxx"
#include "InternalSceneStaticImpl.hxx"
#include "InternalSceneConv.hxx"
#include "InternalSceneImpl.hxx"

void Eifersucht::MeshContext::_Internal_impl::_Cpy_link()
{
	//static _Short_dbg_msg s_szMsg;

	//
	//PrintToCharArray(s_szMsg, "Eifersucht. InternalMeshCtxImpl. Skinning for %s (Mesh)", _m_pAttr->GetNode()->GetName()); 
	//PrintToDebugWindowOnly8(s_szMsg);
	//

	if ( !_Triangulate_mesh() ) 
	{
		PrintToDebugWindowOnly8( 
			"Eifersucht. InternalMeshCtxImpl. "
			"Failed to triangulate mesh." 
			);
		return;
	}

	auto rootNode = _m_pRef->EditChild()->GetParentScene()->GetRootChild();
	_m_pRef->lDeformation.pFaces = (&_m_pRef->vnFaces);
	_m_pRef->lDeformation.pControlPoints = (&_m_pRef->vnControlPoints);
	_Auto_const nSkin = _To_uint _m_pAttr->GetDeformerCount( Fbx::Deformer::eSkin );
	for ( auto uSkin = 0u; uSkin < nSkin; uSkin++ )
	{
		auto skinModifierStatus = Fbx::Status();
		auto skinModifier = new MeshContext::Skin();
		_Auto_const pSkin = FbxCast<Fbx::Skin>( _m_pAttr->GetDeformer(
			uSkin, Fbx::Deformer::eSkin, &skinModifierStatus
			));

		if ( skinModifierStatus.Error() )
		{
			PrintToDebugWindowOnly8( 
				"Eifersucht. InternalMeshCtxImpl. "
				"Failed to resolve skin mesh deformer." 
				);
			PrintToDebugWindowOnly8( 
				skinModifierStatus.GetErrorString() 
				);

			if ( pSkin )
			{
				return;
			}
		}
		else
		{
			skinModifier->pDeformation = (&_m_pRef->lDeformation);
		}

		_Auto_const nBone = _To_uint pSkin->GetClusterCount();

		//
		//PrintToCharArray(s_szMsg, "\tClusters=%d", nBone);
		//PrintToDebugWindowOnly8(s_szMsg);
		//

		for ( auto uBone = 0u; uBone < nBone; uBone++ )
		{
			auto clusterPtr = pSkin->GetCluster(uBone);
			auto boneNodePtr = clusterPtr->GetLink();

			//
			//PrintToCharArray(s_szMsg, "\tLink=%s", boneNodePtr->GetName());
			//PrintToDebugWindowOnly8(s_szMsg);
			//

			if ( clusterPtr )
			{
				auto boneExtractedData = new MeshContext::Bone();
				boneExtractedData->pSkin = skinModifier;

				_Auto_const numEntries = _To_uint clusterPtr->GetControlPointIndicesCount();
				_Auto_const boneWeights = clusterPtr->GetControlPointWeights();
				_Auto_const boneIndices = clusterPtr->GetControlPointIndices();

				boneExtractedData->pWeights = new float32[numEntries];
				boneExtractedData->pIndices = new uint32[numEntries];
				boneExtractedData->uSize = numEntries;

				//
				//PrintToCharArray(s_szMsg, "\t\tDependencies=%d", numEntries); 
				//PrintToDebugWindowOnly8(s_szMsg);
				//

				for ( auto entryIndex = 0u; entryIndex < numEntries; entryIndex++ )
				{

					boneExtractedData->pWeights[entryIndex] = _To_float boneWeights[entryIndex];
					boneExtractedData->pIndices[entryIndex] = _To_uint boneIndices[entryIndex];
					boneExtractedData->pChildTranformation = _m_pRef->m_pRef;

					//
					//PrintToCharArray(s_szMsg, "\t\t\t[%03d] W=%f I=%d", entryIndex, 
					//	boneExtractedData->pWeights[entryIndex], 
					//	boneExtractedData->pIndices[entryIndex]
					//	); 
					//PrintToDebugWindowOnly8(s_szMsg);
					//
				}

				skinModifier->vnBones.push_back(boneExtractedData);

				auto link = rootNode->FindByName(boneNodePtr->GetName());
				if ( link && ( link->GetChildContextType() == SceneChildContext::Type::Bone ) )
				{
					auto boneContext = link->GetTypedChildContext<SkeletonContext>();
					boneExtractedData->pSkeleton = boneContext;

					boneContext->SetFor(
						_m_pRef->GetChild()->GetName(),
						boneExtractedData
						);
				}
				else 
				{
					if (!link) AssertWithMessage(false, "Eifersucht. InternalMeshCtxImpl. Critical: Cannot find the link.");
					else if ( link->GetChildContextType() != SceneChildContext::Type::Bone ) AssertWithMessage(false, "Eifersucht. InternalMeshCtxImpl. Critical: Node type mismatch.");
				}
			}
		}

		_m_pRef->lDeformation.vnSkin.push_back(skinModifier);
	}

	// ....

}